package jinyilw.swing;

import jinyilw.common.SettingTools;
import jinyilw.common.log.LogTools;
import jinyilw.swing.i18n.IString;
import jinyilw.swing.visuals.Rcomp.RColorChooser;

import javax.swing.plaf.ColorUIResource;
import java.awt.Color;
import java.awt.Component;
import java.util.Arrays;

public class ColorTools
{
	public static final int maxColorRoundValue = 512;
	public static final double PI = 3.1415926535897932384626433832795;
	public static final Color transparentColor = new Color(0, 0, 0, 0);
	//public static final Color halfTransColor = new Color(128, 128, 128, 128);
	public static final Color initForeground = new ColorUIResource(0, 0, 0);

	private static int[] circleRGBs;
	private static int[] colorRoundTable;// 色环

	private ColorTools()
	{
	}

	public static String getString(Color color)
	{
		if (color == null)
			return null;
		String r, g, b;
		r = Integer.toHexString(color.getRed()).toUpperCase();
		g = Integer.toHexString(color.getGreen()).toUpperCase();
		b = Integer.toHexString(color.getBlue()).toUpperCase();
		r = r.length() == 1 ? "0" + r : r;
		g = g.length() == 1 ? "0" + g : g;
		b = b.length() == 1 ? "0" + b : b;
		return "#" + r + g + b;
	}

	public static Color getColor(String string)
	{
		return Color.decode(string);
	}

	public static void putColorToDefaultSettings(String name, Color color)
	{
		String colorStr = getString(color);
		SettingTools.putDefaultSettingData(name, colorStr);
		LogTools.info("保存颜色：" + name + "=" + colorStr);
	}

	public static Color getColorFromDefaultSettings(String name, Color defaultColor)
	{
		String string = SettingTools.getDefaultString(name, null);
		if (string != null)
			try
			{
				//LogTools.info("获取颜色：" + name + "=" + string);
				return Color.decode(string);
			} catch (NumberFormatException e)
			{
				LogTools.debug("获取" + name + "颜色出错", e);
			}
		return defaultColor;
	}

	public static Color getAlphaColor(Color c, int opacity)
	{
		if (c == null)
			return null;
		if (opacity >= 255)
			return c;
		if (opacity < 0)
			opacity = 0;
		return new Color(c.getRed(), c.getGreen(), c.getBlue(), opacity);
	}

	private static int[] gradual(int num1, int num2, int length)
	{
		int[] nums = new int[length];
		if (num1 == num2)
		{
			Arrays.fill(nums, num1);
			return nums;
		}
		float step = (float) (num2 - num1) / length;
		for (int i = 0; i < length; i++)
			nums[i] = Math.round(num1 + step * i);
		return nums;
	}

	public static int[] getGradualRGBs(Color c1, Color c2, Color c3, int l1,
			int l2)
	{
		int cR1 = c1.getRed(), cG1 = c1.getGreen(), cB1 = c1.getBlue();
		int cR2 = c2.getRed(), cG2 = c2.getGreen(), cB2 = c2.getBlue();
		int cR3 = c3.getRed(), cG3 = c3.getGreen(), cB3 = c3.getBlue();
		int[] cRs12 = gradual(cR1, cR2, l1);
		int[] cGs12 = gradual(cG1, cG2, l1);
		int[] cBs12 = gradual(cB1, cB2, l1);
		int[] cRs23 = gradual(cR2, cR3, l2);
		int[] cGs23 = gradual(cG2, cG3, l2);
		int[] cBs23 = gradual(cB2, cB3, l2);
		int[] gradualRGBs = new int[l1 + l2];
		int i = 0;
		for (; i < l1; i++)
			gradualRGBs[i] = getRGB(cRs12[i], cGs12[i], cBs12[i]);
		for (int j; i < gradualRGBs.length; i++)
		{
			j = i - l1;
			gradualRGBs[i] = getRGB(cRs23[j], cGs23[j], cBs23[j]);
		}
		return gradualRGBs;
	}

	public static int[] getGradualPixels(Color c1, Color c2, Color c3, int l1,
			int l2)
	{
		int cR1 = c1.getRed(), cG1 = c1.getGreen(), cB1 = c1.getBlue(),
				cA1 = c1.getAlpha();
		int cR2 = c2.getRed(), cG2 = c2.getGreen(), cB2 = c2.getBlue(),
				cA2 = c2.getAlpha();
		int cR3 = c3.getRed(), cG3 = c3.getGreen(), cB3 = c3.getBlue(),
				cA3 = c3.getAlpha();
		int[] cRs12 = gradual(cR1, cR2, l1);
		int[] cGs12 = gradual(cG1, cG2, l1);
		int[] cBs12 = gradual(cB1, cB2, l1);
		int[] cAs12 = gradual(cA1, cA2, l1);
		int[] cRs23 = gradual(cR2, cR3, l2);
		int[] cGs23 = gradual(cG2, cG3, l2);
		int[] cBs23 = gradual(cB2, cB3, l2);
		int[] cAs23 = gradual(cA2, cA3, l2);
		int[] gradualPixels = new int[l1 + l2];
		int i = 0;
		for (; i < l1; i++)
			gradualPixels[i] = getRGB(cRs12[i], cGs12[i], cBs12[i], cAs12[i]);
		for (int j; i < gradualPixels.length; i++)
		{
			j = i - l1;
			gradualPixels[i] = getRGB(cRs23[j], cGs23[j], cBs23[j], cAs23[j]);
		}
		return gradualPixels;
	}

	public static Color[] getGradualColors(Color c1, Color c2, Color c3, int l1,
			int l2)
	{
		int[] pixels = getGradualPixels(c1, c2, c3, l1, l2);
		Color[] colors = new Color[pixels.length];
		for (int i = 0; i < pixels.length; i++)
			colors[i] = new Color(pixels[i], true);
		return colors;
	}

	public static int[] getGradualRGBs(Color c1, Color c2, Color c3, Color c4,
			int l1, int l2, int l3)
	{
		int cR1 = c1.getRed(), cG1 = c1.getGreen(), cB1 = c1.getBlue();
		int cR2 = c2.getRed(), cG2 = c2.getGreen(), cB2 = c2.getBlue();
		int cR3 = c3.getRed(), cG3 = c3.getGreen(), cB3 = c3.getBlue();
		int cR4 = c4.getRed(), cG4 = c4.getGreen(), cB4 = c4.getBlue();
		int[] cRs12 = gradual(cR1, cR2, l1);
		int[] cGs12 = gradual(cG1, cG2, l1);
		int[] cBs12 = gradual(cB1, cB2, l1);
		int[] cRs23 = gradual(cR2, cR3, l2);
		int[] cGs23 = gradual(cG2, cG3, l2);
		int[] cBs23 = gradual(cB2, cB3, l2);
		int[] cRs34 = gradual(cR3, cR4, l3);
		int[] cGs34 = gradual(cG3, cG4, l3);
		int[] cBs34 = gradual(cB3, cB4, l3);
		int[] gradualRGBs = new int[l1 + l2 + l3];
		int i = 0, j;
		for (; i < l1; i++)
			gradualRGBs[i] = getRGB(cRs12[i], cGs12[i], cBs12[i]);
		int ll = l1 + l2;
		for (; i < ll; i++)
		{
			j = i - l1;
			gradualRGBs[i] = getRGB(cRs23[j], cGs23[j], cBs23[j]);
		}
		for (; i < gradualRGBs.length; i++)
		{
			j = i - ll;
			gradualRGBs[i] = getRGB(cRs34[j], cGs34[j], cBs34[j]);
		}
		return gradualRGBs;
	}

	public static int[] createGradualColorSpace(Color[] gradualColors,
			int length)
	{
		int[] gradualColorSpace = new int[length];
		calculateCircleGradualRGBs(gradualColorSpace, gradualColors[0],
				gradualColors[1], gradualColors[2], gradualColors[3]);
		return gradualColorSpace;
	}

	public static void calculateGradualRGBs(int[] gradualRGBs, Color c1,
			Color c2, Color c3, Color c4)
	{
		if (gradualRGBs == null)
			return;
		int l1 = gradualRGBs.length / 3;
		int l2 = l1;
		int l3 = gradualRGBs.length - l2 - l1;
		int cR1 = c1.getRed(), cG1 = c1.getGreen(), cB1 = c1.getBlue();
		int cR2 = c2.getRed(), cG2 = c2.getGreen(), cB2 = c2.getBlue();
		int cR3 = c3.getRed(), cG3 = c3.getGreen(), cB3 = c3.getBlue();
		int cR4 = c4.getRed(), cG4 = c4.getGreen(), cB4 = c4.getBlue();
		int[] cRs12 = gradual(cR1, cR2, l1);
		int[] cGs12 = gradual(cG1, cG2, l1);
		int[] cBs12 = gradual(cB1, cB2, l1);
		int[] cRs23 = gradual(cR2, cR3, l2);
		int[] cGs23 = gradual(cG2, cG3, l2);
		int[] cBs23 = gradual(cB2, cB3, l2);
		int[] cRs34 = gradual(cR3, cR4, l3);
		int[] cGs34 = gradual(cG3, cG4, l3);
		int[] cBs34 = gradual(cB3, cB4, l3);
		int i = 0, j;
		for (; i < l1; i++)
			gradualRGBs[i] = getRGB(cRs12[i], cGs12[i], cBs12[i]);
		int ll = l1 + l2;
		for (; i < ll; i++)
		{
			j = i - l1;
			gradualRGBs[i] = getRGB(cRs23[j], cGs23[j], cBs23[j]);
		}
		for (; i < gradualRGBs.length; i++)
		{
			j = i - ll;
			gradualRGBs[i] = getRGB(cRs34[j], cGs34[j], cBs34[j]);
		}
	}

	public static void calculateCircleGradualRGBs(int[] gradualRGBs, Color c1,
			Color c2, Color c3, Color c4)
	{
		if (gradualRGBs == null)
			return;
		int l1 = gradualRGBs.length / 4;
		int l2 = l1;
		int l3 = l1;
		int l4 = gradualRGBs.length - l3 - l2 - l1;
		int cR1 = c1.getRed(), cG1 = c1.getGreen(), cB1 = c1.getBlue();
		int cR2 = c2.getRed(), cG2 = c2.getGreen(), cB2 = c2.getBlue();
		int cR3 = c3.getRed(), cG3 = c3.getGreen(), cB3 = c3.getBlue();
		int cR4 = c4.getRed(), cG4 = c4.getGreen(), cB4 = c4.getBlue();
		int[] cRs12 = gradual(cR1, cR2, l1);
		int[] cGs12 = gradual(cG1, cG2, l1);
		int[] cBs12 = gradual(cB1, cB2, l1);
		int[] cRs23 = gradual(cR2, cR3, l2);
		int[] cGs23 = gradual(cG2, cG3, l2);
		int[] cBs23 = gradual(cB2, cB3, l2);
		int[] cRs34 = gradual(cR3, cR4, l3);
		int[] cGs34 = gradual(cG3, cG4, l3);
		int[] cBs34 = gradual(cB3, cB4, l3);
		int[] cRs41 = gradual(cR4, cR1, l4);
		int[] cGs41 = gradual(cG4, cG1, l4);
		int[] cBs41 = gradual(cB4, cB1, l4);
		int i = 0, j;
		for (; i < l1; i++)
			gradualRGBs[i] = getRGB(cRs12[i], cGs12[i], cBs12[i]);
		int ll = l1 + l2;
		for (; i < ll; i++)
		{
			j = i - l1;
			gradualRGBs[i] = getRGB(cRs23[j], cGs23[j], cBs23[j]);
		}
		int lll = ll + l3;
		for (; i < lll; i++)
		{
			j = i - ll;
			gradualRGBs[i] = getRGB(cRs34[j], cGs34[j], cBs34[j]);
		}
		for (; i < gradualRGBs.length; i++)
		{
			j = i - lll;
			gradualRGBs[i] = getRGB(cRs41[j], cGs41[j], cBs41[j]);
		}
	}

	public static int[] getCircleRGBs(int length)
	{
		if (circleRGBs != null && circleRGBs.length == length)
			return circleRGBs;
		else
		{
			circleRGBs = new int[length];
			int r , g , b ;
			int p = circleRGBs.length / 6;
			if (circleRGBs.length % 6 > 0)
				p++;
			double step = 255.0 / p;
			for (int i = 0; i < p; i++)
			{
				r = 255;
				g = 0;
				b = (int) (step * i);
				circleRGBs[i] = getRGB(r, g, b);
			}
			for (int i = 0; i < p; i++)
			{
				r = (int) (255 - step * i);
				g = 0;
				b = 255;
				circleRGBs[p + i] = getRGB(r, g, b);
			}
			for (int i = 0; i < p; i++)
			{
				r = 0;
				g = (int) (step * i);
				b = 255;
				circleRGBs[2 * p + i] = getRGB(r, g, b);
			}
			for (int i = 0; i < p; i++)
			{
				r = 0;
				g = 255;
				b = (int) (255 - step * i);
				circleRGBs[3 * p + i] = getRGB(r, g, b);
			}
			for (int i = 0; i < p; i++)
			{
				r = (int) (step * i);
				g = 255;
				b = 0;
				circleRGBs[4 * p + i] = getRGB(r, g, b);
			}
			for (int i = 0, j; i < p; i++)
			{
				r = 255;
				g = (int) (255 - step * i);
				b = 0;
				j = 5 * p + i;
				if (j < circleRGBs.length)
					circleRGBs[j] = getRGB(r, g, b);
			}
			return circleRGBs;
		}
	}

	public static void createFullColorRGBs(int[] circleRGBs, int length)
	{
		int r , g , b ;
		int p = circleRGBs.length / 6;
		if (circleRGBs.length % 6 > 0)
			p++;
		double step = 255.0 / p;
		for (int i = 0; i < p; i++)
		{
			g = 255;
			r = 0;
			b = (int) (step * i);
			circleRGBs[i] = getRGB(r, g, b);
		}
		for (int i = 0; i < p; i++)
		{
			g = (int) (255 - step * i);
			r = 0;
			b = 255;
			circleRGBs[p + i] = getRGB(r, g, b);
		}
		for (int i = 0; i < p; i++)
		{
			g = 0;
			r = (int) (step * i);
			b = 255;
			circleRGBs[2 * p + i] = getRGB(r, g, b);
		}
		for (int i = 0; i < p; i++)
		{
			g = 0;
			r = 255;
			b = (int) (255 - step * i);
			circleRGBs[3 * p + i] = getRGB(r, g, b);
		}
		for (int i = 0; i < p; i++)
		{
			g = (int) (step * i);
			r = 255;
			b = 0;
			circleRGBs[4 * p + i] = getRGB(r, g, b);
		}
		for (int i = 0, j; i < p; i++)
		{
			g = 255;
			r = (int) (255 - step * i);
			b = 0;
			j = 5 * p + i;
			if (j < circleRGBs.length)
				circleRGBs[j] = getRGB(r, g, b);
		}
	}

	public static int getRGB(int r, int g, int b)
	{
		return 0xff << 24 | r << 16 | g << 8 | b;
	}

	public static int getRGB(int r, int g, int b, int a)
	{
		return a << 24 | r << 16 | g << 8 | b;
	}

	/**
	 * 取得透明度
	 */
	public static int getAlpha(int pixel)
	{
		return (pixel >> 24) & 0xff;
	}

	public static int[] randomCircleRGBs(int length)
	{
		int[] RGBs = new int[length];
		if (circleRGBs == null)
			getCircleRGBs(length);
		int startI = (int) (Math.random() * length);
		for (int i = 0; i < length; i++)
			RGBs[i] = circleRGBs[(startI + i) % circleRGBs.length];
		return RGBs;
	}

	public static int[] getColorRoundTable()
	{
		if (colorRoundTable == null)
		{
			colorRoundTable = new int[(maxColorRoundValue + 1) * 2];
			for (int i = 0; i < (maxColorRoundValue + 1) * 2; i++)
				colorRoundTable[i] = roundColor(i - (maxColorRoundValue + 1));
		}
		return colorRoundTable;
	}

	private static int roundColor(int x)
	{
		if (x < 0)
			x = -x;
		while (x > maxColorRoundValue)
			x -= maxColorRoundValue;
		double rd = (Math.sin(x * (2.0 * PI / maxColorRoundValue)) + 1.1) / 2.1;
		int ri = (int) (rd * 255 + 0.5);
		if (ri < 0)
			return 0;
		else if (ri > 255)
			return 255;
		else
			return ri;
	}

	public static Color[] createGradientColors(Color c1, Color c2, int steps)
	{
		if (c1 == null || c2 == null)
			return null;

		Color[] colors = new Color[steps];
		double r = c1.getRed();
		double g = c1.getGreen();
		double b = c1.getBlue();
		double dr = (c2.getRed() - r) / steps;
		double dg = (c2.getGreen() - g) / steps;
		double db = (c2.getBlue() - b) / steps;
		colors[0] = c1;
		for (int i = 1; i < steps - 1; i++)
		{
			r += dr;
			g += dg;
			b += db;
			colors[i] = new Color((int) r, (int) g, (int) b);
		}
		colors[steps - 1] = c2;
		return colors;
	}

	public static Color brighter(Color c, int p)
	{
		if (c == null)
			return null;
		int r = c.getRed();
		int g = c.getGreen();
		int b = c.getBlue();
		int rd = 255 - r;
		int gd = 255 - g;
		int bd = 255 - b;
		r += (rd * p) / 100;
		g += (gd * p) / 100;
		b += (bd * p) / 100;
		return new Color(r, g, b, c.getAlpha());
	}

	public static Color darker(Color c, int p)
	{
		if (c == null)
			return null;
		int r = c.getRed();
		int g = c.getGreen();
		int b = c.getBlue();
		r -= (r * p) / 100;
		g -= (g * p) / 100;
		b -= (b * p) / 100;
		return new Color(r, g, b, c.getAlpha());
	}

	public static Color median(Color c1, Color c2)
	{
		if ((c1 == null || c2 == null))
			return null;
		int r = (c1.getRed() + c2.getRed()) / 2;
		int g = (c1.getGreen() + c2.getGreen()) / 2;
		int b = (c1.getBlue() + c2.getBlue()) / 2;
		int a = (c1.getAlpha() + c2.getAlpha()) / 2;
		return new Color(r, g, b, a);
	}

	public static int getGrayValue(Color c)
	{
		if (c == null)
			return 0;
		int r = c.getRed();
		int g = c.getGreen();
		int b = c.getBlue();
		return Math.min(255, ((r * 299) + (g * 587) + (b * 114)) / 1000);
	}

	public static int getGrayValue(Color[] ca)
	{
		int sum = 0;
		for (Color color : ca)
		{
			sum += getGrayValue(color);
		}
		return (sum / ca.length);
	}

	public static Color toGray(Color c)
	{
		if (c == null)
			return null;
		int gray = getGrayValue(c);
		return new Color(gray, gray, gray, c.getAlpha());
	}
	public static Color showDefaultColorDialog(Component component,
			String title, Color initialColor)
	{
		return RColorChooser.showDefaultDialog(component, title, initialColor);
	}
	public static Color showDefaultColorDialog(Component component,
			IString iTitle, Color initialColor)
	{
		return RColorChooser.showDefaultDialog(component, iTitle, initialColor);
	}
}
